package com.yanqu.road.server.manager.activity.hsisland;

import com.yanqu.road.dao.impl.activity.hsisland.HsIslandEventDataDaoImpl;
import com.yanqu.road.dao.impl.activity.hsisland.HsIslandFloorDataDaoImpl;
import com.yanqu.road.dao.impl.activity.hsisland.HsIslandIslandDataDaoImpl;
import com.yanqu.road.entity.activity.hsisland.HsIslandExploreResult;
import com.yanqu.road.entity.activity.hsisland.HsIslandPosition;
import com.yanqu.road.entity.activity.hsisland.config.HsIslandConfig;
import com.yanqu.road.entity.activity.hsisland.config.HsIslandEventConfig;
import com.yanqu.road.entity.activity.hsisland.config.HsIslandIslandConfig;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandBoxData;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandEventData;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandFloorData;
import com.yanqu.road.entity.activity.hsisland.data.HsIslandIslandData;
import com.yanqu.road.entity.activity.hsisland.enums.HsIslandEventIdEnum;
import com.yanqu.road.entity.activity.hsisland.enums.HsIslandFinishFlagEnum;
import com.yanqu.road.entity.activity.hsisland.enums.HsIslandLatticeTypeEnum;
import com.yanqu.road.entity.activity.hsisland.enums.HsIslandYnFlagEnum;
import com.yanqu.road.exception.BusinessException;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.plot.PlotUtil;
import com.yanqu.road.utils.plot.Point;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class CrossHsIslandIsland {

    /**
     * 岛屿数据
     */
    private HsIslandIslandData islandData;

    /**
     * 事件MAP,k:坐标x_y
     */
    private Map<String, HsIslandEventData> eventMap;

    /**
     * 事件数量MAP,k:事件ID,v:事件数量
     */
    private Map<Integer, Integer> eventNumMap;

    /**
     * 已完结的格子坐标集合
     */
    private Set<String> finishPositionSet;

    /**
     * 移除的事件
     */
    private Map<Integer, HsIslandEventData> delEventMap = new ConcurrentHashMap<>();

    /**
     * 构造方法
     * @param islandData
     * @param eventMap
     */
    public CrossHsIslandIsland(HsIslandIslandData islandData, Map<String, HsIslandEventData> eventMap, Set<String> finishPositionSet, Map<Integer, Integer> eventNumMap) {
        this.islandData = islandData;
        this.eventMap = eventMap;
        this.finishPositionSet = finishPositionSet;
        this.eventNumMap = eventNumMap;
    }

    /**
     * 数据存储
     */
    public void save() {
        //岛屿数据存储
        HsIslandIslandDataDaoImpl islandDataDao = new HsIslandIslandDataDaoImpl();
        if (this.islandData.isInsertOption()) {
            islandDataDao.add(this.islandData);
        } else if (this.islandData.isUpdateOption()) {
            islandDataDao.update(this.islandData);
        }
        //事件数据存储
        HsIslandEventDataDaoImpl eventDataDao = new HsIslandEventDataDaoImpl();
        for (HsIslandEventData eventData : this.eventMap.values()) {
            if (eventData.isInsertOption()) {
                eventDataDao.add(eventData);
            } else if (eventData.isUpdateOption()) {
                eventDataDao.update(eventData);
            }
        }
        //移除的事件数据存储
        Map<Integer, HsIslandEventData> delEventMap;
        synchronized (this.delEventMap) {
            delEventMap = new ConcurrentHashMap<>(this.delEventMap);
            this.delEventMap.clear();
        }
        for (HsIslandEventData eventData : delEventMap.values()) {
            if (eventData.isInsertOption()) {
                eventDataDao.add(eventData);
            } else if (eventData.isUpdateOption()) {
                eventDataDao.update(eventData);
            }
        }
    }

    /**
     * 获取配置
     * @return
     */
    public HsIslandConfig getConfig() {
        return CrossHsIslandActivityMgr.getConfig(this.islandData.getActivityId(), this.islandData.getGroupId());
    }

    /**
     * 获取岛屿数据
     * @return
     */
    public HsIslandIslandData getIslandData() {
        return this.islandData;
    }

    /**
     * 获取事件MAP
     * @return
     */
    public Map<String, HsIslandEventData> getEventMap() {
        return this.eventMap;
    }

    /**
     * 获取事件
     * @param x
     * @param y
     * @return
     */
    public HsIslandEventData getEvent(int x, int y) {
        return this.eventMap.get(x + "_" + y);
    }

    /**
     * 注入事件
     * @param event
     */
    public synchronized void putEvent(HsIslandEventData event) {
        for (HsIslandPosition position : event.getPositions()) {
            this.eventMap.put(position.getKey(), event);
        }
        int eventNum = eventNumMap.getOrDefault(event.getEventId(), 0);
        eventNumMap.put(event.getEventId(), eventNum + 1);
    }

    /**
     * 获取已完结的事件MAP
     * @return
     */
    public Set<String> getFinishEventSet() {
        return this.finishPositionSet;
    }

    /**
     * 获取事件数量
     * @param eventId
     * @return
     */
    public int getEventNum(int eventId) {
        return this.eventNumMap.getOrDefault(eventId, 0);
    }

    /**
     * 添加海神之心
     */
    public synchronized void addKeyNum() {
        this.islandData.setKeyNum(this.islandData.getKeyNum() + 1);
    }

    /**
     * 判断格子是否已经完结
     * @param x
     * @param y
     * @return
     */
    public boolean checkPositionFinish(int x, int y) {
        String key = x + "_" + y;
        if (this.finishPositionSet.contains(key)) {
            return true;
        }
        return false;
    }

    /**
     * 判断格子是否连通
     * @param x
     * @param y
     * @return
     */
    public boolean checkPositionLink(int x, int y) {
        boolean flag = false;
        //获取岛屿配置
        HsIslandIslandConfig islandConfig = this.getConfig().getIslandConfig(this.islandData.getIslandId());
        //获取给定x和y坐标周围上下左右的4个地块
        List<Point> points = PlotUtil.getAdjacentPoints(x, y);
        for (Point point : points) {
            String position = point.getX() + "," + point.getY();
            Integer positionType = islandConfig.getPositionType(position);
            if (positionType != null) {
                //判断一下是否是明灯开启的坐标
                boolean lightFlag = this.isLightOpenPosition(point.getX(), point.getY());
                if (lightFlag) {
                    continue;
                }
                //相邻出生点，连通
                if (positionType == HsIslandLatticeTypeEnum.LATTICE_TYPE_BORN.getType()) {
                    flag = true;
                    break;
                }
                //相邻事件完结点，连通
                boolean finishFlag = this.checkPositionFinish(point.getX(), point.getY());
                if (finishFlag) {
                    flag = true;
                    break;
                }
                //有事件，连通
                HsIslandEventData event = this.getEvent(point.getX(), point.getY());
                if (event != null) {
                    flag = true;
                    break;
                }
            }
        }
        return flag;
    }

    /**
     * 判断坐标是否已经有事件
     * @param x
     * @param y
     * @return
     */
    public boolean checkPositionHasEvent(int x, int y) {
        String key = x + "_" + y;
        if (this.eventMap.containsKey(key)) {
            return true;
        }
        if (this.finishPositionSet.contains(key)) {
            return true;
        }
        return false;
    }

    /**
     * 移除事件
     * @param event
     */
    public void removeEvent(HsIslandEventData event) {
        for (HsIslandPosition position : event.getPositions()) {
            HsIslandEventData delEvent = this.eventMap.remove(position.getKey());
            if (delEvent != null) {
                this.delEventMap.put(delEvent.getEventUnId(), delEvent);
            }
        }
    }

    /**
     * 完结事件
     * @param event
     */
    public void finishEvent(HsIslandEventData event) {
        //更新事件完结
        event.setFinishFlag(HsIslandFinishFlagEnum.FINISH_YES.getType());
        //已完结事件集合添加
        for (HsIslandPosition position : event.getPositions()) {
            this.finishPositionSet.add(position.getKey());
        }
        //移除事件
        boolean removeFlag = true;
        //未领取奖励的PVE事件，领取完奖励才移除
        if (event.getEventId() == HsIslandEventIdEnum.EVENT_PVE.getType() || event.getEventId() == HsIslandEventIdEnum.EVENT_PVE_BIG.getType()) {
            if (event.getRewardFlag() == HsIslandYnFlagEnum.NOT.getType()) {
                removeFlag = false;
            }
        }
        if (removeFlag) {
            //移除事件
            this.removeEvent(event);
        }
    }

    /**
     * 判断是否可以出海神之心
     * @return
     */
    public boolean checkCanExploreKey() {
        //总事件数量
        int allNum = this.getAllEventNum();
        //已有事件数
        int hasEventNum = this.getExploredEventNum();
        BigDecimal hasRate = BigDecimal.valueOf(hasEventNum).divide(BigDecimal.valueOf(allNum), 8, BigDecimal.ROUND_UP);
        //比较的比例
        BigDecimal checkRate = BigDecimal.valueOf(this.islandData.getKeyShowRate()).divide(BigDecimal.valueOf(1000), 8, BigDecimal.ROUND_UP);
        //判断
        if (hasRate.compareTo(checkRate) >= 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取已探索过的格子坐标集合
     * @return
     */
    public Set<String> getExploredLaSet() {
        Set<String> exploredPositionSet = new HashSet<>();
        //未完结的事件
        exploredPositionSet.addAll(this.eventMap.keySet());
        //已完结的事件
        exploredPositionSet.addAll(this.finishPositionSet);
        return exploredPositionSet;
    }

    /**
     * 获取岛屿总格子数量
     * @return
     */
    public int getAllLaNum() {
        return this.islandData.getAllLaNum();
    }

    /**
     * 获取已探索过的格子数量
     * @return
     */
    public int getExploredLaNum() {
        return this.getExploredLaSet().size();
    }

    /**
     * 获取岛屿点亮进度，千分比（格子比）
     * @return
     */
    public int getLightProgress() {
        //总格子数量
        int allNum = this.getAllLaNum();
        //已探索过的格子数量
        int hasNum = this.getExploredLaNum();
        return BigDecimal.valueOf(hasNum).divide(BigDecimal.valueOf(allNum), 8, RoundingMode.UP).multiply(BigDecimal.valueOf(1000)).intValue();
    }

    /**
     * 获取非固定的可探索的格子数量（排除掉宝箱格子，4格子事件）
     * @return
     */
    public int getCanExploreLaNum(Map<String, HsIslandBoxData> boxDataMap) {
        Set<String> allHasPositionSet = new HashSet<>();
        //已探索过的格子
        Set<String> exploredLaSet = this.getExploredLaSet();
        allHasPositionSet.addAll(exploredLaSet);
        //宝箱坐标格子
        if (boxDataMap != null) {
            allHasPositionSet.addAll(boxDataMap.keySet());
        }
        //4格事件坐标
        allHasPositionSet.addAll(this.islandData.getFourLaPositions().keySet());
        //格子总数量
        int allNum = this.getAllLaNum();
        return allNum - allHasPositionSet.size();
    }

    /**
     * 获取岛屿总事件数量
     * @return
     */
    public int getAllEventNum() {
        return this.islandData.getAllEventNum();
    }

    /**
     * 获取岛屿探索过的事件数量
     * @return
     */
    public int getExploredEventNum() {
        int allEventNum = 0;
        for (int eventNum : eventNumMap.values()) {
            allEventNum += eventNum;
        }
        return allEventNum;
    }

    /**
     * 获取岛屿探索进度，千分比（事件比）
     * @return
     */
    public int getExploreProgress() {
        //总事件数量
        int allNum = this.getAllEventNum();
        //探索过的事件数量
        int hasNum = this.getExploredEventNum();
        return BigDecimal.valueOf(hasNum).divide(BigDecimal.valueOf(allNum), 8, RoundingMode.UP).multiply(BigDecimal.valueOf(1000)).intValue();
    }

    /**
     * 记录明灯开启的坐标组
     * @param exploreResultList
     */
    public void addLightPositions(List<HsIslandExploreResult> exploreResultList) {
        //明灯开启的坐标组
        Set<String> lightPositionSet = new HashSet<>();
        //事件LIST
        for (HsIslandExploreResult exploreResult : exploreResultList) {
            for (HsIslandEventData eventData : exploreResult.getEventDataList()) {
                for (HsIslandPosition position : eventData.getPositions()) {
                    lightPositionSet.add(position.getKey());
                }
            }
        }
        if (lightPositionSet.isEmpty()) {
            return;
        }
        //记录下明灯开启的坐标组
        this.islandData.addLightPosition(lightPositionSet);
        //检测一下，开启的坐标组是否连通
        boolean linkFlag = false;
        for (String positionStr :lightPositionSet) {
            String[] positionStrArr = positionStr.split("_");
            int x = Integer.parseInt(positionStrArr[0]);
            int y = Integer.parseInt(positionStrArr[1]);
            boolean oneLinkFlag = this.checkPositionLink(x, y);
            if (oneLinkFlag) {
                linkFlag = true;
            }
        }

        //明灯开启的事件不连通，记录下明灯开启的坐标组
        if (linkFlag) {
            //连通
            this.islandData.removeLightPosition(lightPositionSet);
            //检测一下，是否触发连通
            for (String positionStr :lightPositionSet) {
                String[] positionStrArr = positionStr.split("_");
                int x = Integer.parseInt(positionStrArr[0]);
                int y = Integer.parseInt(positionStrArr[1]);
                this.checkLightPositionsLink(x, y);
            }
        }
    }

    /**
     * 是否是明灯开启的坐标
     * @param x
     * @param y
     * @return
     */
    public boolean isLightOpenPosition(int x, int y) {
        for (Set<String> positions : this.islandData.getLightPositionList()) {
            if (positions.contains(x + "_" + y)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取明灯开启的坐标组
     * @param x
     * @param y
     * @return
     */
    public Set<String> getLightPositionSet(int x, int y) {
        for (Set<String> positions : this.islandData.getLightPositionList()) {
            if (positions.contains(x + "_" + y)) {
                return positions;
            }
        }
        return null;
    }

    /**
     * 检测明灯开启的坐标组是否连通
     * @param x 已连通的x
     * @param y 已连通的y
     */
    public void checkLightPositionsLink(int x, int y) {
        boolean removeFlag = false;
        Set<String> removeLightPositionSet = new HashSet<>();
        //判断上下左右，是否有明灯开启的坐标
        List<Point> points = PlotUtil.getAdjacentPoints(x, y);
        for (Point point : points) {
            Set<String> lightPositionSet = this.getLightPositionSet(point.getX(), point.getY());
            if (lightPositionSet != null) {
                boolean flag = this.islandData.removeLightPosition(lightPositionSet);
                if (flag) {
                    removeFlag = true;
                    removeLightPositionSet.addAll(lightPositionSet);
                }
            }
        }
        //有连通，继续检测是否有其他的连通
        if (removeFlag) {
            for (String removePositionStr : removeLightPositionSet) {
                String[] removePositionStrArr = removePositionStr.split("_");
                int removeX = Integer.parseInt(removePositionStrArr[0]);
                int removeY = Integer.parseInt(removePositionStrArr[1]);
                this.checkLightPositionsLink(removeX, removeY);
            }
        }
    }

    /**
     * 判断是否必出海神之心
     * @return
     */
    public boolean checkMustShowKey() {
        //获取探索进度千分比
        int exploreProgress = this.getExploreProgress();
        if (exploreProgress >= this.islandData.getKeyMustShowRate() && this.islandData.getKeyNum() <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取海神之心命中增加的权重
     * @return
     */
    public int getExploreKeyWeight() {
        //获取探索进度千分比
        int exploreProgress = this.getExploreProgress();
        return this.getConfig().getKeyShowAddWeight(exploreProgress);
    }
}
